home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume19 / pclcomp / part02 < prev    next >
Encoding:
Internet Message Format  |  1991-05-02  |  55.6 KB

  1. From: tony@sdd.hp.com (Tony Parkhurst)
  2. Newsgroups: comp.sources.misc
  3. Subject: v19i014:  pclcomp - HP-PCL graphics compression filter for printers., Part02/02
  4. Message-ID: <1991May2.172454.13851@sparky.IMD.Sterling.COM>
  5. Date: 2 May 91 17:24:54 GMT
  6. Approved: kent@sparky.imd.sterling.com
  7. X-Checksum-Snefru: dac0950d 1ef5dd6c 23039c04 276d9bb2
  8.  
  9. Submitted-by: Tony Parkhurst <tony@sdd.hp.com>
  10. Posting-number: Volume 19, Issue 14
  11. Archive-name: pclcomp/part02
  12.  
  13. #! /bin/sh
  14. # This is a shell archive.  Remove anything before this line, then feed it
  15. # into a shell via "sh file" or similar.  To overwrite existing files,
  16. # type "sh file -c".
  17. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  18. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  19. # Contents:  pclcomp.c
  20. # Wrapped by kent@sparky on Thu May  2 12:17:56 1991
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. echo If this archive is complete, you will see the following message:
  23. echo '          "shar: End of archive 2 (of 2)."'
  24. if test -f 'pclcomp.c' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'pclcomp.c'\"
  26. else
  27.   echo shar: Extracting \"'pclcomp.c'\" \(52617 characters\)
  28.   sed "s/^X//" >'pclcomp.c' <<'END_OF_FILE'
  29. X/*
  30. X**  Pclcomp -- PCL compression filter.
  31. X**
  32. X**  If you have any problems or errors to report, please send them to me:
  33. X**
  34. X**  Tony Parkhurst  
  35. X** 
  36. X**  Email address:  tony@sdd.hp.com    -or-   hp-sdd!tony
  37. X**
  38. X**  Please send a copy of the graphic file that is a problem, and the version
  39. X**  of pclcomp you are using.
  40. X**
  41. X**  All suggestions and requests are welcome.
  42. X*/
  43. X
  44. X/*
  45. X ***************************************************************************
  46. X *
  47. X * $Source: /disc/44/cgtriton/tony/filters/pclcomp/RCS/pclcomp.c,v $ 
  48. X * $Date: 91/04/30 09:41:24 $ 
  49. X * $Revision: 1.28 $
  50. X *
  51. X * Description:    Compresses pcl graphics files.
  52. X *
  53. X * Author:       Tony Parkhurst
  54. X * Created:      890427
  55. X * Language:     C
  56. X *
  57. X * (c) Copyright 1989, Hewlett-Packard Company, all rights reserved.
  58. X *
  59. X ***************************************************************************
  60. X */
  61. X
  62. X
  63. X/*
  64. X ***************************************************************************
  65. X *
  66. X * $Log:    pclcomp.c,v $
  67. X * Revision 1.28  91/04/30  09:41:24  09:41:24  tony (Tony Parkhurst)
  68. X * Now puts stdin and stdout in binary mode for MSDOS.
  69. X *     Changes courtesy of Mike Slomin.
  70. X * Changed usage message a bit.
  71. X * 
  72. X * Revision 1.27  91/04/23  15:48:05  15:48:05  tony (Tony Parkhurst)
  73. X * Added handling of plus_sign in value fields.
  74. X * 
  75. X * Revision 1.26  91/04/23  09:47:11  09:47:11  tony (Tony Parkhurst)
  76. X * Pass thru unknown modes.
  77. X * 
  78. X * Revision 1.25  91/04/18  11:09:27  11:09:27  tony (Tony Parkhurst)
  79. X * Added parse for fractions in values (i.e. <esc>(s16.67H)
  80. X * 
  81. X * Revision 1.24  91/04/10  14:16:30  14:16:30  tony (Tony Parkhurst)
  82. X * strips text and control codes between <esc>*rA and <esc>*rB w/ -s option
  83. X * 
  84. X * Revision 1.23  91/04/05  14:53:25  14:53:25  tony (Tony Parkhurst)
  85. X * Added fixed for deskjet
  86. X * Also added a stripping feature.
  87. X * 
  88. X * Revision 1.22  91/04/05  08:48:53  08:48:53  tony (Tony Parkhurst)
  89. X * Added some error checkin on output for MS-DOS users.
  90. X * 
  91. X * Revision 1.21  91/04/04  12:53:32  12:53:32  tony (Tony Parkhurst)
  92. X * Replaced parser.
  93. X *    Now handles combined escape sequences.
  94. X *    Now handles downloads.
  95. X *    Now combines mode changes with data.
  96. X * 
  97. X * Revision 1.20  91/04/04  08:02:12  08:02:12  tony (Tony Parkhurst)
  98. X * Removed some test code.
  99. X * 
  100. X * Revision 1.19  91/03/25  14:38:48  14:38:48  tony (Tony Parkhurst)
  101. X * Changed defaults.
  102. X * 
  103. X * Revision 1.18  91/03/25  14:31:22  14:31:22  tony (Tony Parkhurst)
  104. X * Re-worked memory allocation stuff for funky input files.
  105. X * 
  106. X * Revision 1.17  91/03/25  13:50:19  13:50:19  tony (Tony Parkhurst)
  107. X * Use command line args for file w/o -i or -o.
  108. X * 
  109. X * Revision 1.16  91/03/04  14:23:15  14:23:15  tony (Tony Parkhurst)
  110. X * Fixed to allow ONLY mode 3 if the user really wants it.
  111. X * 
  112. X * Revision 1.15  91/03/04  14:08:23  14:08:23  tony (Tony Parkhurst)
  113. X * Added an exit(0) at the end of main.
  114. X * fixed up some zerostrip stuff.
  115. X * made mode 3 the highest priority mode.
  116. X * 
  117. X * Revision 1.14  91/02/20  13:57:27  13:57:27  tony (Tony Parkhurst)
  118. X * Changed priority a bit.
  119. X * Added some zerostripping for mode 2.
  120. X * 
  121. X * Revision 1.13  91/02/06  15:31:00  15:31:00  tony (Tony Parkhurst)
  122. X * oops.
  123. X * 
  124. X * Revision 1.12  91/02/06  14:41:28  14:41:28  tony (Tony Parkhurst)
  125. X * fixed usage message
  126. X * 
  127. X * Revision 1.11  91/02/06  14:38:10  14:38:10  tony (Tony Parkhurst)
  128. X * Added file input and output for MS-DOS.
  129. X * 
  130. X * Revision 1.10  91/02/05  17:49:23  17:49:23  tony (Tony Parkhurst)
  131. X * Fixed problem with zero stripped input.
  132. X * 
  133. X * Revision 1.9  91/02/05  16:11:39  16:11:39  tony (Tony Parkhurst)
  134. X * Removed delay code and bitfield stuff.
  135. X * 
  136. X * Revision 1.8  91/02/05  11:04:53  11:04:53  tony (Tony Parkhurst)
  137. X * Added io delay stuff for triton.
  138. X * 
  139. X * Revision 1.7  91/02/05  10:28:32  10:28:32  tony (Tony Parkhurst)
  140. X * Fix for someone specifing ONLY mode 3.
  141. X * 
  142. X * Revision 1.6  91/01/29  14:13:09  14:13:09  tony (Tony Parkhurst)
  143. X * Updated some comments.
  144. X * 
  145. X * Revision 1.5  91/01/29  13:26:24  13:26:24  tony (Tony Parkhurst)
  146. X * Cleaned up, revamped a bit.
  147. X * 
  148. X * Revision 1.4  89/11/09  15:59:16  15:59:16  tony (Tony Parkhurst)
  149. X * Fix for esc * r U coming after esc * r A.
  150. X * 
  151. X * Revision 1.3  89/10/24  11:31:12  11:31:12  tony (Tony Parkhurst)
  152. X * Added parsing of <esc>*rC
  153. X * 
  154. X * Revision 1.2  89/10/13  09:56:46  09:56:46  tony (Tony Parkhurst)
  155. X * Completely revamped by Greg G.
  156. X * 
  157. X * Revision 1.1  89/06/15  13:57:46  13:57:46  tony (Tony Parkhurst)
  158. X * Initial revision
  159. X * 
  160. X *
  161. X ***************************************************************************
  162. X */
  163. Xstatic char *rcs_id="$Header: pclcomp.c,v 1.28 91/04/30 09:41:24 tony Exp $";
  164. X
  165. Xstatic char *rev_id="$Revision: 1.28 $";
  166. Xstatic char *author="Copyright (c) 1991, Tony Parkhurst";
  167. X
  168. X/* This program takes a PCL graphics file and will try and
  169. X * optimize the compression.
  170. X */
  171. X
  172. X/*
  173. X *   This program was first a filter by Dean to compress pcl graphics.
  174. X *
  175. X *   This program now will do optimal compression using modes 0,1,2 and 3
  176. X *
  177. X *   Also, this program will take compressed input.
  178. X *
  179. X *   Input and output formats are standard pcl.
  180. X *
  181. X *   Imaging files will be compressed too.
  182. X *
  183. X *   pclcomp does not take advantage of Y-Offset for blank areas.  
  184. X *   This is because Y-Offset creates white areas, but we don't do enough
  185. X *   parsing to determine what value "white" has.  An application that
  186. X *   can assume white values could make use of this sequence.
  187. X *
  188. X *   pclcomp does not do any of the block compression modes (4-8).
  189. X *
  190. X *   There are a few obvious inefficiencies that I will fix later.
  191. X *
  192. X *   Speaking of mode 3, there is a possible problem because each of the
  193. X *   output row storage areas are 2* size of what mode 0 would be.  This
  194. X *   is clearly sufficient for modes 1 and 2, but it may not be for mode
  195. X *   3.  But I cannot think of a case in Mode 3 where this would be a problem.
  196. X *
  197. X *   An additional enhancement would be to compare all the planes in a
  198. X *   multi-plane file (color) and if nothing changed, using mode 3, just
  199. X *   output a single <esc>*b0W.
  200. X */
  201. X
  202. X/*
  203. X *   Usage:  pclcomp [-v] [-0] [-1] [-2] [-3] [-z] [-n###] < infile > outfile
  204. X *
  205. X *   Pclcomp will do graphics compression based on compression modes 0, 1, 2
  206. X *   and 3.  (Mode 0 is uncompressed).  Pclcomp will accept all modes, and
  207. X *   will attempt to optimize by selecting the best output mode for each
  208. X *   row (or plane) of data.  By default, pclcomp will use all 4 modes, but
  209. X *   the user may restrict which output modes to use with the -0123 options.
  210. X *   For example, to use pclcomp for output to a PaintJet which only knows
  211. X *   modes 0 and 1 (the XL also understands modes 2 and 3), one would use:
  212. X *
  213. X *      pclcomp -01 < infile > outfile
  214. X *
  215. X *   Note:  Mode 0 should always be allowed.  None of the other modes is
  216. X *   guaranteed to be better than mode 0 in all cases.
  217. X *
  218. X *   The 'v' option tells the number of rows (planes) of data input and output
  219. X *   in the different modes (to stderr).
  220. X *
  221. X *   The 'z' option is useful for PaintJet files using only modes 0 and 1, it
  222. X *   does zero "stripping" as the PaintJet will do zero "filling".
  223. X *   NOTE: 'z' now means do NOT zerostrip.
  224. X *
  225. X *   The 'n' option is to change the default number of pixels in a picture.
  226. X *   The proper way to set the pixel width is with the source raster width
  227. X *   sequence <esc*r#S>, but soo many applications just assume the default,
  228. X *   which is different on different printers, so I am providing this
  229. X *   command line option to set a new default.  One could also change the
  230. X *   DEFAULT constant below (make sure it is a multiple of 8).  Currently
  231. X *   it is set to 8" at 180 dpi (1440), but for 300 dpi, set it to 2400.
  232. X *
  233. X *   default is now 2400 (for 300dpi ala LaserJet).
  234. X */
  235. X
  236. X#include <stdio.h>
  237. X#include <string.h>
  238. X
  239. X#ifdef MSDOS
  240. X#include <fcntl.h>
  241. X#endif
  242. X
  243. X
  244. X/* This flag is for code that uses bitfields for 68000 systems */
  245. X#define BITFIELDS 0
  246. X
  247. X#define Get_Character() getchar()
  248. X
  249. X#define MIN(x,y)    ( ((x) < (y)) ? (x) : (y) )
  250. X
  251. X#define TRUE 1
  252. X#define FALSE 0
  253. X
  254. X#define ESC    27
  255. X
  256. X#define DEFAULT 2400        /* default width in pixels (multiple of 8) */
  257. X
  258. X#define MAXMODES  4
  259. X#define MAXPLANES 8
  260. X#define MAXBYTES 60000        /* now mostly meaningless, just a big number */
  261. X
  262. Xunsigned char    *seed_row[MAXPLANES];
  263. Xunsigned char    *new_row;
  264. Xunsigned char    *out_row[MAXMODES];
  265. Xunsigned int    out_size[MAXMODES];
  266. X
  267. Xchar    memflag = FALSE;    /* set when memory has been allocated */
  268. X
  269. X
  270. Xchar    mode0=FALSE,
  271. X    mode1=FALSE,
  272. X    mode2=FALSE,
  273. X    mode3=FALSE;
  274. X
  275. Xunsigned char    num_planes=1;
  276. Xunsigned char    curr_plane=0;
  277. X
  278. Xchar    imaging = FALSE;        /* not imaging, so no lockout */
  279. X
  280. Xchar    verbose = FALSE;
  281. X
  282. Xunsigned char    inmode = 0;        /* input compression mode */
  283. Xunsigned char    outmode = 0;        /* output compression mode */
  284. X
  285. Xunsigned int    rasterwidth=DEFAULT/8;    /* width of picture, in bytes */
  286. Xunsigned int    rpix = DEFAULT;        /* width of picture, in pixels */
  287. X
  288. Xunsigned char    invert=FALSE;        /* invert the data (obsolete) */
  289. X
  290. Xunsigned char    zerostrip= TRUE;    /* strip trailing zeros */
  291. X
  292. Xunsigned int    inuse[4]={0,0,0,0}, outuse[4] = {0,0,0,0};
  293. X
  294. Xchar    widthwarning = FALSE;    /* for trucation warning */
  295. Xchar    firstrow = TRUE;    /* to prevent mode 3 from being first */
  296. X
  297. X
  298. Xstruct {            /* this will hold the data for the  */
  299. X     unsigned char model;    /* configuring of image processing   */
  300. X     unsigned char pix_mode;
  301. X     unsigned char inx_bits;
  302. X     unsigned char red;
  303. X     unsigned char green;
  304. X     unsigned char blue;
  305. X     short wr;
  306. X     short wg;
  307. X     short wb;
  308. X     short br;
  309. X     short bg;
  310. X     short bb; 
  311. X} imdata;
  312. X
  313. Xextern    unsigned char *malloc();
  314. X
  315. Xchar    *filein = NULL, *fileout = NULL;
  316. X
  317. X/*
  318. X**  These variables are for the new parser.
  319. X**  The new parser handles more sequences, and also deals with combined
  320. X**  escape sequences better.
  321. X*/
  322. X
  323. Xint    parameter;
  324. Xint    group_char;
  325. Xint    terminator;
  326. Xint    old_terminator;
  327. Xint    value;
  328. Xint    frac;
  329. Xint    scanf_count;
  330. Xchar    in_sequence = FALSE;
  331. Xchar    pass_seq;
  332. Xchar    plus_sign;        /* for relative values */
  333. X
  334. X
  335. X/* dummy buffer */
  336. Xchar buf[BUFSIZ];
  337. X
  338. X/*
  339. X**  If the printer is a DeskJet, then we must handle <esc>*rB differently
  340. X**  Option '-d' will turn on this mode.
  341. X*/
  342. X
  343. Xchar    deskjet = FALSE;
  344. X
  345. X
  346. X/*
  347. X**  Many drivers it seems put <esc>*rB<esc>*rA between each and every row
  348. X**  of data.  This defeats compression mode 3 on a DeskJet, and also
  349. X**  makes the PaintJet (not XL) quite slow.  This next flag "-s" on the
  350. X**  command line, will attempt to do a reasonable job of stripping
  351. X**  out the excess commands.
  352. X**
  353. X**  The in_graphics flag will be used to strip unwanted control chars from
  354. X**  the file.
  355. X*/
  356. X
  357. Xchar    strip_seq = FALSE;
  358. Xchar    in_graphics = FALSE;
  359. X
  360. X
  361. X/*
  362. X**  Just for certain special cases, it would be nice to append an <esc>E reset
  363. X**  to the end of the job.  Specify with "-r".
  364. X*/
  365. X
  366. Xchar    reset_seq = FALSE;
  367. X
  368. X
  369. Xchar    *progname;        /* to hold the program name for verbose */
  370. X
  371. X
  372. X
  373. X/*
  374. X**
  375. X**        Main program.
  376. X**
  377. X*/
  378. X
  379. Xmain(argc, argv)
  380. Xint argc;
  381. Xchar *argv[];
  382. X{
  383. X  int    c,j;
  384. X  extern char *optarg;
  385. X  extern int   optind;
  386. X
  387. X    progname = argv[0];
  388. X
  389. X#ifdef MSDOS
  390. X    setmode(fileno(stdin), O_BINARY);    /* Place stdin and stdout in */
  391. X    setmode(fileno(stdout), O_BINARY);    /* binary mode. (Mike Slomin)*/
  392. X#endif
  393. X
  394. X    /* parse up the args here */
  395. X
  396. X  while ((c = getopt(argc, argv, "0123drsvzn:i:o:s")) != EOF )
  397. X    switch(c){
  398. X    case '0':
  399. X            mode0++;
  400. X            break;
  401. X    case '1':
  402. X            mode1++;
  403. X            break;
  404. X    case '2':
  405. X            mode2++;
  406. X            break;
  407. X    case '3':
  408. X            mode3++;
  409. X            break;
  410. X    case 'd':
  411. X            deskjet++;
  412. X            break;
  413. X    case 'r':
  414. X            reset_seq++;
  415. X            break;
  416. X    case 's':
  417. X            strip_seq++;
  418. X            break;
  419. X    case 'v':
  420. X            verbose++;
  421. X            break;
  422. X    case 'z':
  423. X            zerostrip = FALSE;
  424. X            break;
  425. X    case 'n':
  426. X            rpix = atoi(optarg);    /* new default */
  427. X            rasterwidth = (rpix + 7) / 8;    /* round up */
  428. X            break;
  429. X
  430. X    case 'i':
  431. X            filein = optarg;
  432. X            break;
  433. X    case 'o':
  434. X            fileout = optarg;
  435. X            break;
  436. X
  437. X    case '?':
  438. X    default:
  439. X            fprintf(stderr, "Usage: %s [-0123drsvz] [-n###] [infile [outfile]]\n",
  440. X                argv[0]);
  441. X            exit(-1);
  442. X    };
  443. X
  444. X    if ( verbose )
  445. X    {
  446. X        fprintf(stderr, "%s: %s\n", argv[0], rev_id);
  447. X    }
  448. X
  449. X
  450. X  if ( ! ( mode0 || mode1 || mode2 || mode3) )    /* any modes on? */
  451. X    mode0 = mode1 = mode2 = mode3 = TRUE;    /* all  modes by default */
  452. X
  453. X    /*
  454. X    **  Check to see if any file args were given on the command line.
  455. X    **  Ones that were not preceded by a "-i" or "-o".
  456. X    */
  457. X
  458. X    if ( filein == NULL && optind < argc && argv[optind] != NULL )
  459. X        filein = argv[optind++];
  460. X
  461. X    if ( fileout == NULL && optind < argc && argv[optind] != NULL )
  462. X        fileout = argv[optind++];
  463. X
  464. X    /*
  465. X    **  Now open files for stdin and stdout if provided by the user.
  466. X    */
  467. X
  468. X    if ( filein != NULL )        /* new input file */
  469. X
  470. X        if ( freopen( filein, "rb", stdin ) == NULL )
  471. X        {
  472. X            fprintf(stderr,"Unable to open %s for input.\n",filein);
  473. X            exit(-42);
  474. X        }
  475. X
  476. X    if ( fileout != NULL )        /* new output file */
  477. X
  478. X        if ( freopen( fileout, "wb", stdout ) == NULL )
  479. X        {
  480. X            fprintf(stderr, "Unable to open %s for output.\n",
  481. X                fileout);
  482. X            exit(-43);
  483. X        }
  484. X
  485. X
  486. X    /*
  487. X    **  This is the pcl input parsing loop.
  488. X    */
  489. X
  490. X    while( ( c = getchar() ) != EOF )
  491. X    {
  492. X
  493. X        /*  Ignore all chars until an escape char  */
  494. X
  495. X        /*
  496. X        **  If we are in graphics, toss it if strip_seq is set.
  497. X        */
  498. X
  499. X        if ( c != ESC )
  500. X        {
  501. X            if ( !strip_seq || !in_graphics )
  502. X                putchar(c);    /* pass it thru */
  503. X
  504. X            continue;    /* pop to the top of the loop */
  505. X        }
  506. X
  507. X        /*
  508. X        **  Now we have an escape sequence, get the parameter char.
  509. X        */
  510. X
  511. X        parameter = getchar();
  512. X
  513. X        if ( parameter == EOF )        /* oops */
  514. X        {
  515. X            putchar ( ESC );
  516. X            fprintf(stderr, "Warning:  File ended with <esc>.\n");
  517. X            break;            /* unexpected end of input */
  518. X        }
  519. X
  520. X        /*
  521. X        **  Now check to see if it is a two character sequence.
  522. X        */
  523. X
  524. X        if ( parameter >= '0' && parameter <= '~' )
  525. X        {
  526. X            putchar ( ESC );
  527. X            putchar ( parameter );        /* pass it thru */
  528. X
  529. X            /*
  530. X            **  If the second character is an E, then we
  531. X            **  and the printer do a reset.
  532. X            */
  533. X
  534. X            if ( parameter == 'E' )
  535. X            {
  536. X                free_mem();
  537. X                curr_plane = 0;
  538. X                num_planes = 1;
  539. X                imaging = FALSE;
  540. X                inmode = 0;
  541. X                outmode = 0;
  542. X                in_graphics = FALSE;
  543. X
  544. X                /* can't do this if user gave value with -n.
  545. X                rasterwidth = DEFAULT/8;
  546. X                rpix = DEFAULT;
  547. X                */
  548. X            }
  549. X
  550. X            continue;        /* return to the top */
  551. X        }
  552. X
  553. X        /*
  554. X        **  Now check to make sure that the parameter character is
  555. X        **  within range.
  556. X        */
  557. X
  558. X        if ( parameter < '!' || parameter > '/' )
  559. X        {
  560. X            putchar ( ESC );
  561. X            putchar ( parameter );
  562. X
  563. X            fprintf(stderr, "Warning:  Invalid escape sequence.\n");
  564. X
  565. X            continue;
  566. X        }
  567. X
  568. X        /*
  569. X        **  We are only interested in certain parameters, so pass
  570. X        **  the rest of the sequences.
  571. X        */
  572. X
  573. X        /*
  574. X        **  For the moment, we are only interested in '*' (graphics)
  575. X        **  '(' and ')' (downloads).  Although we do not do anything
  576. X        **  with downloads, we need to pass the binary data thru
  577. X        **  untouched.
  578. X        **  Also, '&' is handled too.
  579. X        */
  580. X
  581. X        if ( parameter != '*' && parameter != '(' 
  582. X            && parameter != ')' && parameter != '&' )
  583. X        {
  584. X            putchar ( ESC );
  585. X            putchar ( parameter );
  586. X            Flush_To_Term();        /* flush rest of seq. */
  587. X            continue;
  588. X        }
  589. X
  590. X
  591. X        /*
  592. X        **  Parameter character is in range, look for a valid group char
  593. X        */
  594. X
  595. X        group_char = getchar();
  596. X
  597. X        if ( group_char == EOF )    /* oops, ran out of input */
  598. X        {
  599. X            putchar ( ESC );
  600. X            putchar ( parameter );
  601. X
  602. X            fprintf(stderr, "Warning:  Incomplete escape sequence.\n");
  603. X            break;
  604. X        }
  605. X
  606. X        /*
  607. X        **  See if in proper range.  If it isn't, it is not an error
  608. X        **  because the group character is optional for some sequences.
  609. X        **  For the moment, we are not interested in those sequences,
  610. X        **  so pass them thru.
  611. X        */
  612. X
  613. X        if ( group_char < '`' || group_char > '~' )
  614. X        {
  615. X            putchar ( ESC );
  616. X            putchar ( parameter );
  617. X            putchar ( group_char );
  618. X            if ( group_char < '@' || group_char > '^' )
  619. X                Flush_To_Term();    /* pass rest of seq. */
  620. X            continue;
  621. X        }
  622. X
  623. X        /*
  624. X        **  Now we have a valid group character, decide if we want
  625. X        **  to deal with this escape sequence.
  626. X        **
  627. X        **  Sequences we want do deal with include:
  628. X        **
  629. X        **    <esc>*r    ** graphics
  630. X        **    <esc>*b    ** graphics
  631. X        **    <esc>*v    ** graphics
  632. X        **
  633. X        **  Sequences we must pass thru binary data:
  634. X        **
  635. X        **    <esc>*c    ** pattern
  636. X        **    <esc>*t    ** obsolete
  637. X        **    <esc>(f    ** download char set
  638. X        **    <esc>(s    ** download char
  639. X        **    <esc>)s    ** download font
  640. X        **    <esc>&a    ** logical page
  641. X        **    <esc>&l    ** obsolete
  642. X        **
  643. X        */
  644. X
  645. X        if (  ( parameter == '*'
  646. X            && group_char != 'r' && group_char != 'b' 
  647. X            && group_char != 'v' && group_char != 'c' 
  648. X            && group_char != 't' )
  649. X           || ( parameter == '&'
  650. X            && group_char != 'a' && group_char != 'l' )
  651. X           || ( parameter == '(' 
  652. X            && group_char != 'f' && group_char != 's' )
  653. X           || ( parameter == ')' && group_char != 's' ) )
  654. X        {
  655. X            /*
  656. X            **  Definately not interested in the sequence.
  657. X            */
  658. X
  659. X            putchar ( ESC );
  660. X            putchar ( parameter );
  661. X            putchar ( group_char );
  662. X            Flush_To_Term();
  663. X            continue;
  664. X        }
  665. X
  666. X        /*
  667. X        **  Now set up a pass thru flag so we can ignore the entire
  668. X        **  sequences of some of these.
  669. X        */
  670. X
  671. X        if ( parameter != '*' )
  672. X            pass_seq = TRUE;
  673. X        else if ( group_char == 'c' || group_char == 't' )
  674. X            pass_seq = TRUE;
  675. X        else
  676. X            pass_seq = FALSE;
  677. X
  678. X
  679. X        /*
  680. X        **  Now we have a sequence that we are definately interested in.
  681. X        **
  682. X        **  Get the value field and terminator, and loop until final
  683. X        **  terminator is found.
  684. X        */
  685. X
  686. X        do
  687. X        {
  688. X            /* first see if the value has a plus sign */
  689. X
  690. X            scanf_count = scanf(" + %d", &value );
  691. X
  692. X            if ( scanf_count == 1 )
  693. X
  694. X                plus_sign = TRUE;
  695. X            else
  696. X            {
  697. X                plus_sign = FALSE;
  698. X
  699. X                scanf_count = scanf(" %d", &value );
  700. X
  701. X                if ( scanf_count == 0 )
  702. X                    value = 0;        /* by default */
  703. X            }
  704. X
  705. X            terminator = getchar();
  706. X
  707. X            /*
  708. X            ** check to see if a fractional parameter was passed.
  709. X            */
  710. X
  711. X            frac = 0;    /* in case no fraction */
  712. X
  713. X            if ( terminator == '.' )
  714. X            {
  715. X                /*
  716. X                **  Need to get fractional part.
  717. X                **
  718. X                **  This will not work properly if the
  719. X                **  fraction is < .1 (i.e. a leading 0 is
  720. X                **  present).  For example, the value
  721. X                **  14.05 for point size, which would get
  722. X                **  rounded to 14.00 for scalable fonts,
  723. X                **  would get passed thru as 14.5 which is
  724. X                **  rounded to 14.5.  This is unlikely to
  725. X                **  happen as the 14.05 case is rare, but
  726. X                **  it is valid PCL, so I will fix this
  727. X                **  in the future.
  728. X                */
  729. X
  730. X                if ( scanf("%d", &frac) != 1 )
  731. X                {
  732. X                    frac = 0;    /* no frac? */
  733. X                }
  734. X
  735. X                /*
  736. X                **  Now get the real terminator.
  737. X                */
  738. X
  739. X                terminator = getchar();
  740. X            }
  741. X
  742. X
  743. X            if ( terminator == EOF )    /* barf */
  744. X            {
  745. X                fprintf(stderr, "Warning:  Incomplete sequence at end of file.\n");
  746. X                break;
  747. X            }
  748. X
  749. X            /*
  750. X            **  If the pass_seq flag is set, then just pass
  751. X            **  it thru to stdout until a 'W' is found.
  752. X            */
  753. X
  754. X            if ( pass_seq )
  755. X            {
  756. X                /*
  757. X                **  If not in sequence, then we output esc
  758. X                **  otherwise, output the saved terminator.
  759. X                */
  760. X
  761. X                if ( !in_sequence )
  762. X                {
  763. X                    in_sequence = TRUE;
  764. X                    putchar ( ESC );
  765. X                    putchar ( parameter );
  766. X                    putchar ( group_char );
  767. X                } else
  768. X                {
  769. X                    putchar ( old_terminator );
  770. X                }
  771. X
  772. X                /* now pass the value */
  773. X
  774. X                if ( plus_sign )
  775. X                    putchar('+');
  776. X
  777. X                if ( scanf_count )    /* there was a value */
  778. X                    printf("%0d", value);
  779. X                
  780. X                /* need to output the fractional part */
  781. X
  782. X                if ( frac )
  783. X                    printf(".%0d", frac);
  784. X
  785. X                /*
  786. X                **  We save the terminator, because we may
  787. X                **  need to change it to upper case.
  788. X                */
  789. X
  790. X                old_terminator = terminator;
  791. X
  792. X                /* if binary data, pass it thru */
  793. X
  794. X                if ( terminator == 'W' )    /* aha */
  795. X                {
  796. X                    putchar ( terminator );
  797. X                    in_sequence = FALSE;    /* terminates */
  798. X                    Flush_Bytes ( value );    /* pass data */
  799. X                }
  800. X
  801. X                continue;
  802. X            }
  803. X
  804. X            /*
  805. X            **  Ok, this is a sequence we want to pay attention to.
  806. X            **
  807. X            **  Do_Graphics returns TRUE if we need to pass seq.
  808. X            **
  809. X            **  Note:  Do_Graphics modifies the parser vars such
  810. X            **         as in_sequence.  This is because it may
  811. X            **         have to output stuff directly.
  812. X            */
  813. X
  814. X            if ( Do_Graphics ( group_char, value, terminator ) )
  815. X            {
  816. X                /*
  817. X                **  If not in sequence, then we output esc
  818. X                **  otherwise, output the saved terminator.
  819. X                */
  820. X
  821. X                if ( !in_sequence )
  822. X                {
  823. X                    in_sequence = TRUE;
  824. X                    putchar ( ESC );
  825. X                    putchar ( parameter );
  826. X                    putchar ( group_char );
  827. X                } else
  828. X                {
  829. X                    putchar ( old_terminator );
  830. X                }
  831. X
  832. X                /* now pass the value */
  833. X
  834. X                if ( plus_sign )
  835. X                    putchar('+');
  836. X
  837. X                if ( scanf_count )    /* there was a value */
  838. X                    printf("%0d", value);
  839. X
  840. X                /* need to output the fractional part */
  841. X
  842. X                if ( frac )
  843. X                    printf(".%0d", frac);
  844. X
  845. X                /*
  846. X                **  We save the terminator, because we may
  847. X                **  need to change it to upper case.
  848. X                */
  849. X
  850. X                old_terminator = terminator;
  851. X            }
  852. X
  853. X        } while ( terminator >= '`' && terminator <= '~' );
  854. X
  855. X        /*
  856. X        ** The oppsite test (above) may be more appropriate.  That is, 
  857. X        ** !(terminator >= '@' && terminator <= '^').
  858. X        */
  859. X        
  860. X        /*
  861. X        **  If we were in a sequence, then we must terminate it.
  862. X        **  If it was lower case, then it must be uppered.
  863. X        */
  864. X
  865. X        if ( in_sequence )
  866. X        {
  867. X            putchar ( terminator & 0xdf );        /* a ==> A */
  868. X            in_sequence = FALSE;
  869. X        }
  870. X    }
  871. X    
  872. X
  873. X    /*
  874. X    **  If the user wants a reset, give him one.
  875. X    */
  876. X
  877. X    if ( reset_seq )
  878. X    {
  879. X        putchar ( ESC );
  880. X        putchar ( 'E' );
  881. X    }
  882. X
  883. X
  884. X    /*
  885. X    **  Finished up, so print stats and close output file.
  886. X    */
  887. X
  888. X    fclose(stdout);
  889. X
  890. X
  891. X    if ( verbose )
  892. X    {
  893. X        for(j = 0; j < 4; j++)
  894. X            fprintf(stderr,"Rows in mode %1d: %d\n", j, inuse[j]);
  895. X        for(j = 0; j < 4; j++)
  896. X            fprintf(stderr,"Rows out mode %1d: %d\n", j, outuse[j]);
  897. X    }
  898. X
  899. X    exit(0);
  900. X}
  901. X
  902. X
  903. X/*
  904. X**  Do_Graphics() takes the graphics escape sequence and performs the
  905. X**  necessary functions.
  906. X**  TRUE is returned if the escape sequence needs to be passed to the output.
  907. X*/
  908. X
  909. Xint    Do_Graphics( group, num, terminator )
  910. Xint    group, num, terminator;
  911. X{
  912. X
  913. X    /*  first look at vW  */
  914. X
  915. X    if ( group == 'v' )
  916. X
  917. X        if ( terminator != 'W' )
  918. X            
  919. X            return ( TRUE );    /* pass it thru */
  920. X        else
  921. X        {
  922. X            if ( !in_sequence )
  923. X            {
  924. X                putchar ( ESC );
  925. X                putchar ( parameter );
  926. X                putchar ( group );
  927. X            } else
  928. X                putchar ( old_terminator );
  929. X
  930. X            in_sequence = FALSE;        /* terminating */
  931. X
  932. X            printf("%0d", num);
  933. X            putchar ( terminator );
  934. X
  935. X            free_mem();    /* reset memory */
  936. X
  937. X            imaging++;
  938. X
  939. X            fread(&imdata, MIN(num, 18), 1, stdin);
  940. X            fwrite(&imdata, MIN(num, 18), 1, stdout);
  941. X
  942. X            num -= MIN(num, 18);
  943. X
  944. X            /* copy rest of unknown data */
  945. X
  946. X            if ( num > 0 )
  947. X                Flush_Bytes(num);
  948. X
  949. X
  950. X            switch(imdata.pix_mode){
  951. X                case 0x00:
  952. X                    rasterwidth = (rpix + 7)/8;
  953. X                    num_planes = imdata.inx_bits;
  954. X                    break;
  955. X                case 0x01:
  956. X                    rasterwidth = rpix*imdata.inx_bits/8;
  957. X                    break;
  958. X                case 0x02:
  959. X                    rasterwidth = (rpix + 7)/8;
  960. X                    num_planes =imdata.red + imdata.green +
  961. X                                imdata.blue;
  962. X                    break;
  963. X                case 0x03:
  964. X                    rasterwidth = (imdata.red +
  965. X                                   imdata.green +
  966. X                                   imdata.blue)*rpix/8;
  967. X                    break;
  968. X            }
  969. X
  970. X            return ( FALSE );
  971. X        }
  972. X
  973. X    /*
  974. X    **  Now deal with <esc>*r stuff
  975. X    */
  976. X
  977. X    if ( group == 'r' )
  978. X    {
  979. X        switch ( terminator )
  980. X        {
  981. X            case 'A':
  982. X            case 'a':
  983. X
  984. X                /* in graphics mode, may do stripping */
  985. X                in_graphics = TRUE;
  986. X
  987. X                /* if user wants to strip redundant seq */
  988. X                if ( strip_seq && memflag )
  989. X                    return( FALSE );
  990. X
  991. X                curr_plane=0;
  992. X                zero_seeds();    /* may allocate mem */
  993. X                break;
  994. X
  995. X            case 'C':
  996. X            case 'c':
  997. X
  998. X                /* not in graphics disable code strip */
  999. X
  1000. X                in_graphics = FALSE;
  1001. X
  1002. X                if ( strip_seq )
  1003. X                    return( FALSE );
  1004. X
  1005. X                inmode = 0;
  1006. X                outmode = 0;
  1007. X
  1008. X                free_mem();
  1009. X                curr_plane=0;
  1010. X                break;
  1011. X
  1012. X            case 'B':
  1013. X            case 'b':
  1014. X
  1015. X                /* not in graphics disable code strip */
  1016. X
  1017. X                in_graphics = FALSE;
  1018. X
  1019. X                if ( strip_seq )
  1020. X                    return( FALSE );
  1021. X
  1022. X                if ( deskjet )    /* B resets modes on DJ */
  1023. X                {
  1024. X                    inmode = 0;
  1025. X                    outmode = 0;
  1026. X                }
  1027. X                free_mem();
  1028. X                curr_plane=0;
  1029. X                break;
  1030. X
  1031. X            case 'S':
  1032. X            case 's':
  1033. X
  1034. X                /* free mem in case widths changed */
  1035. X                free_mem();
  1036. X
  1037. X                rpix = num;
  1038. X
  1039. X                if (imaging){
  1040. X                    switch(imdata.pix_mode)
  1041. X                    {
  1042. X                        case 0x00:
  1043. X                            rasterwidth=(rpix+7)/8;
  1044. X                            break;
  1045. X                        case 0x01:
  1046. X                            rasterwidth = 
  1047. X                             rpix*imdata.inx_bits/8;
  1048. X                            break;
  1049. X                        case 0x02:
  1050. X                            rasterwidth=(rpix+7)/8;
  1051. X                            break;
  1052. X                        case 0x03:
  1053. X                            rasterwidth = 
  1054. X                              (imdata.red 
  1055. X                              + imdata.green
  1056. X                              + imdata.blue)*rpix/8;
  1057. X                            break;
  1058. X                    }
  1059. X                } else
  1060. X                    rasterwidth = (num + 7) / 8;
  1061. X                break;
  1062. X
  1063. X            case 'T':
  1064. X            case 't':
  1065. X                break;
  1066. X
  1067. X            case 'U':
  1068. X            case 'u':
  1069. X                curr_plane=0;
  1070. X                free_mem();    /* if ESC*rA came first */
  1071. X                num_planes = num;
  1072. X                imaging = FALSE;    /* goes off */
  1073. X                break;
  1074. X
  1075. X            default:
  1076. X                break;
  1077. X        }
  1078. X
  1079. X        return ( TRUE );        /* pass sequence on */
  1080. X
  1081. X    }    /* group r */
  1082. X
  1083. X    /*
  1084. X    **  Last and final group 'b'.  All the graphics data comes thru here.
  1085. X    */
  1086. X
  1087. X
  1088. X    switch ( terminator )
  1089. X    {
  1090. X           case 'm':
  1091. X           case 'M':
  1092. X            inmode = num;
  1093. X            return ( FALSE );    /* we do NOT pass this */
  1094. X            break;
  1095. X
  1096. X           /*
  1097. X           **  <esc>*b#X is obsolete, don't bother with it. 
  1098. X           **  If I did do something, then I would zero part of the
  1099. X           **  seed rows.
  1100. X           */
  1101. X
  1102. X           case 'x':
  1103. X           case 'X':
  1104. X            break;
  1105. X
  1106. X           case 'y':
  1107. X           case 'Y':
  1108. X            /* zero only if allocated */
  1109. X            if ( memflag )
  1110. X                zero_seeds();
  1111. X            break;
  1112. X
  1113. X           case 'W':
  1114. X            if(!memflag)
  1115. X                zero_seeds();        /* get memory */
  1116. X
  1117. X            /* fire up sequence */
  1118. X
  1119. X            if ( !in_sequence )
  1120. X            {
  1121. X                putchar ( ESC );
  1122. X                putchar ( parameter );
  1123. X                putchar ( group );
  1124. X            } else
  1125. X                putchar ( old_terminator );
  1126. X
  1127. X            in_sequence = FALSE;        /* terminating */
  1128. X
  1129. X            if(curr_plane < num_planes) 
  1130. X            {
  1131. X
  1132. X                Process(num, 'W');
  1133. X
  1134. X                if ( curr_plane + 1 < num_planes )
  1135. X                {
  1136. X                    /* now we have a problem */
  1137. X                    zero_upper(curr_plane + 1);
  1138. X                }
  1139. X            } else
  1140. X                Process_extra(num,'W');   
  1141. X
  1142. X            curr_plane=0;
  1143. X
  1144. X            return ( FALSE );
  1145. X
  1146. X            break;
  1147. X
  1148. X           case 'V':
  1149. X            if(!memflag)
  1150. X                zero_seeds();        /* get memory */
  1151. X            
  1152. X            /*
  1153. X            **  If curr_plane is the last plane, this should
  1154. X            **  be a 'W', not a 'V'.  I could change it,
  1155. X            **  then I would fix Process_extra() to not output
  1156. X            **  anything as the 'W' was already sent.
  1157. X            */
  1158. X
  1159. X            if( curr_plane < num_planes ) 
  1160. X            {
  1161. X                /* fire up sequence */
  1162. X
  1163. X                if ( !in_sequence )
  1164. X                {
  1165. X                    putchar ( ESC );
  1166. X                    putchar ( parameter );
  1167. X                    putchar ( group );
  1168. X                } else
  1169. X                    putchar ( old_terminator );
  1170. X
  1171. X                in_sequence = FALSE;    /* terminating */
  1172. X            
  1173. X
  1174. X                Process(num, 'V');
  1175. X                curr_plane++;
  1176. X            } else
  1177. X                Process_extra(num,'V');
  1178. X
  1179. X            return ( FALSE );
  1180. X
  1181. X            break;
  1182. X
  1183. X        default:
  1184. X            break;
  1185. X    }
  1186. X
  1187. X    return ( TRUE );        /* pass sequence */
  1188. X}
  1189. X
  1190. X
  1191. X
  1192. X/*
  1193. X**  Flush_To_Term() simply passes thru input until a valid terminator
  1194. X**  character is found.  This is for unwanted escape sequences.
  1195. X*/
  1196. X
  1197. XFlush_To_Term()
  1198. X{
  1199. X    int    c;
  1200. X
  1201. X    do
  1202. X    {
  1203. X        c = getchar();
  1204. X
  1205. X        if ( c == EOF )            /* this is a problem */
  1206. X            return;
  1207. X        
  1208. X        putchar ( c );
  1209. X
  1210. X    } while ( c < '@' || c > '^' );
  1211. X}
  1212. X
  1213. X
  1214. X/*
  1215. X**  Flush_Bytes() simply transfers so many bytes directly from input to output.
  1216. X**  This is used to pass thru binary data that we are not interested in so that
  1217. X**  it will not confuse the parser.  I.e. downloads.
  1218. X*/
  1219. X
  1220. XFlush_Bytes( num )
  1221. Xunsigned int    num;
  1222. X{
  1223. X    int    bnum;
  1224. X
  1225. X    while ( num > 0 )
  1226. X    {
  1227. X        bnum = MIN ( BUFSIZ, num );
  1228. X
  1229. X        fread( buf, 1, bnum, stdin );
  1230. X
  1231. X        if ( fwrite( buf, 1, bnum, stdout ) < bnum )
  1232. X
  1233. X            /* check for error and exit */
  1234. X
  1235. X            if ( ferror(stdout) )
  1236. X            {
  1237. X                perror("Output error");
  1238. X                exit(-2);
  1239. X            }
  1240. X
  1241. X        num -= bnum;
  1242. X    }
  1243. X}
  1244. X
  1245. X
  1246. X
  1247. X
  1248. X/*----------------------------------------*/
  1249. X
  1250. X/*
  1251. X**    Zero_seeds() will allocate and initialize memory.
  1252. X**    If memory has already been allocated, then it will just initialize it.
  1253. X*/
  1254. X
  1255. X
  1256. Xzero_seeds()
  1257. X{
  1258. X    int r;
  1259. X
  1260. X    /* first allocate and init seed_rows for number of planes. */
  1261. X
  1262. X    for ( r = 0; r < num_planes ; r++)
  1263. X    {
  1264. X        if(!memflag)
  1265. X        {
  1266. X            seed_row[r] = (unsigned char *) malloc(rasterwidth);
  1267. X
  1268. X            if ( seed_row[r] == NULL )
  1269. X            {
  1270. X                fprintf(stderr, "Out of memory.\n");
  1271. X                exit(-3);
  1272. X            }
  1273. X        }
  1274. X
  1275. X        /* zero seeds for mode 3 */
  1276. X
  1277. X        memset(seed_row[r], 0, rasterwidth);
  1278. X    }
  1279. X
  1280. X
  1281. X    if(!memflag)
  1282. X    {
  1283. X        new_row = (unsigned char *) malloc(rasterwidth);
  1284. X
  1285. X        if ( new_row == NULL )
  1286. X        {
  1287. X            fprintf(stderr, "Out of memory.\n");
  1288. X            exit(-3);
  1289. X        }
  1290. X
  1291. X        for(r=0; r<MAXMODES; r++)
  1292. X        {
  1293. X            /* 2 * width is needed for modes 1, 2 and 3 */
  1294. X
  1295. X            out_row[r] = (unsigned char *) malloc(2 * rasterwidth);
  1296. X
  1297. X            if ( out_row[r] == NULL )
  1298. X            {
  1299. X                fprintf(stderr, "Out of memory.\n");
  1300. X                exit(-3);
  1301. X            }
  1302. X        }
  1303. X
  1304. X    }
  1305. X
  1306. X    memset(new_row, 0, rasterwidth);
  1307. X
  1308. X    memflag = TRUE;            /* memory is in place */
  1309. X}
  1310. X
  1311. X
  1312. X/* this routine if for incomplete transfers of data */
  1313. X
  1314. Xzero_upper(plane)
  1315. Xint    plane;
  1316. X{
  1317. X    int i;
  1318. X
  1319. X    /* assume memory already present */
  1320. X
  1321. X    for ( i = plane; i < num_planes; i++)
  1322. X        memset(seed_row[i], 0, rasterwidth);
  1323. X}
  1324. X
  1325. X
  1326. XProcess(inbytes, terminator)
  1327. Xint inbytes, terminator;
  1328. X{
  1329. X
  1330. X    int insize;
  1331. X    int minmode = 0;
  1332. X
  1333. X    inuse[inmode]++;
  1334. X
  1335. X    switch ( inmode ) {
  1336. X
  1337. X    case 0:
  1338. X        if ( !widthwarning && inbytes > rasterwidth )
  1339. X        {
  1340. X            /* This is likely to result in data truncation. */
  1341. X            widthwarning = TRUE;
  1342. X            fprintf(stderr,"Warning: Input pixel width exceeds expected width.\n");
  1343. X        }
  1344. X
  1345. X        insize = Mode_0_Graphics(inbytes,rasterwidth,new_row,invert);
  1346. X        break;
  1347. X    case 1:
  1348. X        insize = Mode_1_Graphics(inbytes,rasterwidth,new_row,invert);
  1349. X        break;
  1350. X    case 2:
  1351. X        insize = Mode_2_Graphics(inbytes,rasterwidth,new_row,invert);
  1352. X        break;
  1353. X    case 3:
  1354. X        memcpy(new_row, seed_row[curr_plane], rasterwidth);
  1355. X        insize = Mode_3_Graphics(inbytes,rasterwidth,new_row,invert);
  1356. X        break;
  1357. X
  1358. X    default:        /* unknown mode? */
  1359. X
  1360. X        /*  Don't know what to do about seed rows, pass stuff thru */
  1361. X
  1362. X        fprintf(stderr, "%s: Unsupported compression mode %d.\n",
  1363. X            progname, inmode );
  1364. X
  1365. X        ChangeMode(inmode);    /* go to that mode */
  1366. X
  1367. X        /* <esc>*b has already been output */
  1368. X
  1369. X        printf("%1d%c", inbytes, terminator);
  1370. X
  1371. X        Flush_Bytes( inbytes );
  1372. X
  1373. X        firstrow = TRUE;        /* pop it out of mode 3 */
  1374. X
  1375. X        /*  Go ahead and clear the seed rows if present  */
  1376. X        if ( memflag )
  1377. X            zero_seeds();
  1378. X
  1379. X        return;
  1380. X
  1381. X    }
  1382. X
  1383. X
  1384. X    /*
  1385. X    **
  1386. X    */
  1387. X
  1388. X    if ( mode0 )
  1389. X        /* actually, this is redundant since new_row is mode 0 */
  1390. X        out_size[0] = Output_0( new_row, out_row[0], rasterwidth );
  1391. X    else
  1392. X        out_size[0] = MAXBYTES+1;
  1393. X
  1394. X    if ( mode1 )
  1395. X        out_size[1] = Output_1( new_row, out_row[1], rasterwidth );
  1396. X    else
  1397. X        out_size[1] = MAXBYTES+1;
  1398. X
  1399. X    if ( mode2 )
  1400. X        out_size[2] = Output_2( new_row, out_row[2], rasterwidth );
  1401. X    else
  1402. X        out_size[2] = MAXBYTES+1;
  1403. X
  1404. X    if ( mode3 )
  1405. X        out_size[3] = Output_3( seed_row[curr_plane], new_row, out_row[3], rasterwidth );
  1406. X    else
  1407. X        out_size[3] = MAXBYTES+1;
  1408. X    
  1409. X
  1410. X    /*
  1411. X    **  Now determine which mode will give the best output.  Note that it
  1412. X    **  takes 5 bytes to change modes, so we penalize all modes that are
  1413. X    **  not the current output by 5 bytes.  This is to discourage changing
  1414. X    **  unless the benifit is worth it.  The exception to this rule is
  1415. X    **  mode 3.  We want to encourage going to mode 3 because of the seed
  1416. X    **  row behaviour.  That is, if we have a simple picture that does
  1417. X    **  not change much, and say each of the sizes for modes 1 and 2 always
  1418. X    **  comes out to 4 bytes of data, then if we add 5 to mode 3 each time,
  1419. X    **  it would never get selected.  But, we remove the penalty, and if
  1420. X    **  mode 3 is selected (0 bytes of data needed for mode 3), then each
  1421. X    **  succesive row only needs 0 bytes of data.  For a 300 dpi A size
  1422. X    **  picture with 3 data planes, this could be a savings of 37k bytes.
  1423. X    */
  1424. X
  1425. X    /*
  1426. X    **  With the new parser, the output to change modes is now only
  1427. X    **  2 bytes, since it gets combined with the *b#W sequence.
  1428. X    **  So, I decided to ignore the switching penalty.
  1429. X    */
  1430. X
  1431. X    /*
  1432. X    **  Due to a possible bug in PaintJet XL, don't allow mode 3 to be
  1433. X    **  selected for the first row of output.  But do allow it if the
  1434. X    **  user has no other mode selected.
  1435. X    */
  1436. X
  1437. X    if ( firstrow && (mode0 || mode1 || mode2) )
  1438. X    {
  1439. X        out_size[3] = MAXBYTES+1;    /* disable mode 3 for now */
  1440. X
  1441. X        if ( terminator == 'W' )    /* last plane? */
  1442. X            firstrow = FALSE;    /* no longer first row */
  1443. X    }
  1444. X
  1445. X
  1446. X    minmode = 3;
  1447. X
  1448. X    if ( out_size[2] < out_size[minmode] )
  1449. X        minmode = 2;
  1450. X
  1451. X    if ( out_size[1] < out_size[minmode] )
  1452. X        minmode = 1;
  1453. X
  1454. X    if ( out_size[0] < out_size[minmode] )
  1455. X        minmode = 0;
  1456. X
  1457. X
  1458. X                    /* I may remove this sometime */
  1459. X    if ( minmode != outmode )
  1460. X        if ( out_size[minmode] == out_size[outmode] )
  1461. X            minmode = outmode;
  1462. X
  1463. X
  1464. X    outuse[minmode]++;
  1465. X
  1466. X    if ( outmode != minmode )
  1467. X        ChangeMode( minmode );
  1468. X    
  1469. X    /* <esc>*b has already been output */
  1470. X
  1471. X    printf("%1d%c", out_size[minmode], terminator);
  1472. X
  1473. X    if ( fwrite( out_row[minmode], 1, out_size[minmode], stdout) < 
  1474. X                            out_size[minmode] )
  1475. X
  1476. X        /* check for error and exit */
  1477. X
  1478. X        if ( ferror(stdout) )
  1479. X        {
  1480. X            perror("Output error");
  1481. X            exit(-2);
  1482. X        }
  1483. X
  1484. X
  1485. X    memcpy(seed_row[curr_plane], new_row, rasterwidth);
  1486. X
  1487. X}
  1488. X
  1489. XProcess_extra(bytes, terminator)
  1490. Xint bytes;
  1491. Xchar terminator;
  1492. X{
  1493. X    int  i;
  1494. X
  1495. X    /* toss any excess data */
  1496. X
  1497. X    for(i = 0; i < bytes; i++)
  1498. X       getchar();
  1499. X
  1500. X    /* last plane? force move down to next row */
  1501. X
  1502. X    if(terminator == 'W')
  1503. X    {
  1504. X        /* <esc>*b has already been output */
  1505. X        printf("0W");
  1506. X
  1507. X        firstrow = FALSE;        /* not on first row anymore */
  1508. X
  1509. X    }
  1510. X
  1511. X}
  1512. X
  1513. XChangeMode(newmode)
  1514. Xint newmode;
  1515. X{
  1516. X    /*
  1517. X    **  <esc>*b have already been output.
  1518. X    **  terminator is 'm' instead of 'M' since will be followed by 'W'
  1519. X    */
  1520. X    printf("%1dm", newmode);
  1521. X    outmode = newmode;
  1522. X}
  1523. X
  1524. X
  1525. X/* these decoders came from graphics.c in the gp parser */
  1526. X
  1527. X
  1528. X/* $PAGE$ */
  1529. X/*-----------------------------------------------------------------------*\
  1530. X |                                                                       |
  1531. X |  Function Name: Mode_0_Graphics                                       |
  1532. X |                                                                       |
  1533. X |  Description:                                                         |
  1534. X |                                                                       |
  1535. X |  This is the routine that handles a Mode 0 graphics block transfer    |
  1536. X |  to the Formatter Module.                                             |
  1537. X |                                                                       |
  1538. X\*-----------------------------------------------------------------------*/
  1539. X
  1540. X/* FUNCTION */
  1541. X
  1542. XMode_0_Graphics(input_bytes, output_bytes, address, invert)
  1543. X
  1544. Xunsigned int
  1545. X   input_bytes,                 /* Count of bytes to be read. */
  1546. X   output_bytes;                /* Count of bytes to be stored. */
  1547. X
  1548. Xunsigned char
  1549. X   *address;                    /* Pointer to where to store bytes. */
  1550. X
  1551. Xunsigned char            /* Boolean to request data inversion */
  1552. X    invert;
  1553. X
  1554. X{
  1555. X   /* LOCAL VARIABLES */
  1556. X
  1557. X   unsigned char
  1558. X      *store_ptr;               /* Pointer to where to store the byte. */
  1559. X
  1560. X   unsigned int
  1561. X      read_bytes,               /* Local copy of input_bytes. */
  1562. X      write_bytes;              /* Local copy of output_bytes. */
  1563. X
  1564. X   /* CODE */
  1565. X
  1566. X   /* Initialize the local variables. */
  1567. X
  1568. X   read_bytes = input_bytes;
  1569. X   write_bytes = output_bytes;
  1570. X   store_ptr = address;
  1571. X   
  1572. X
  1573. X   /* transfer the lesser of available bytes or available room */
  1574. X
  1575. X   if (invert)
  1576. X     Inv_Transfer_Block( MIN(write_bytes,read_bytes), store_ptr);
  1577. X   else
  1578. X     Transfer_Block( MIN(write_bytes,read_bytes), store_ptr);
  1579. X
  1580. X   /* now zero fill or throw excess data away */
  1581. X
  1582. X   if ( read_bytes > write_bytes )
  1583. X      Discard_Block(read_bytes - write_bytes);        /* throw excess */
  1584. X   else {
  1585. X      store_ptr += read_bytes;                /* adjust pointer */
  1586. X      write_bytes -= read_bytes;            /* zero fill count */
  1587. X
  1588. X      memset(store_ptr, 0, write_bytes);
  1589. X   }
  1590. X
  1591. X   return ( input_bytes );
  1592. X}
  1593. X
  1594. X/* $PAGE$ */
  1595. X/*-----------------------------------------------------------------------*\
  1596. X |                                                                       |
  1597. X |  Function Name: Mode_1_Graphics                                       |
  1598. X |                                                                       |
  1599. X |  Description:                                                         |
  1600. X |                                                                       |
  1601. X |  This is the routine that handles a Mode 1 graphics block transfer    |
  1602. X |  to the Formatter Module.  Mode 1 graphics is a compacted mode.       |
  1603. X |  The data in Mode 1 is in pairs.  The first byte is a replicate       |
  1604. X |  count and the second byte is the data.  The data byte is stored      |
  1605. X |  then replicated the replicate count.  Therefore a replicate count    |
  1606. X |  of 0 means the data byte is stored once.  The input byte count       |
  1607. X |  must be an even amount for the data to be in byte pairs.             |
  1608. X |                                                                       |
  1609. X\*-----------------------------------------------------------------------*/
  1610. X
  1611. X/* FUNCTION */
  1612. X
  1613. XMode_1_Graphics(input_bytes, output_bytes, address, invert)
  1614. X
  1615. Xunsigned int
  1616. X   input_bytes,                 /* Count of bytes to be read. */
  1617. X   output_bytes;                /* Count of bytes to be stored. */
  1618. X
  1619. Xunsigned char
  1620. X   *address;                    /* Pointer to where to store bytes. */
  1621. X
  1622. Xunsigned char            /* Boolean to request data inversion */
  1623. X    invert;
  1624. X
  1625. X{
  1626. X   /* LOCAL VARIABLES */
  1627. X
  1628. X   unsigned char
  1629. X      *store_ptr,               /* Pointer to where to store the byte. */
  1630. X      input_char;               /* Byte to be replicated. */
  1631. X
  1632. X   unsigned int
  1633. X      read_bytes,               /* Local copy of input_bytes. */
  1634. X      write_bytes;              /* Local copy of output_bytes. */
  1635. X
  1636. X   int
  1637. X      replicate_count;          /* Number of times to replicate data. */
  1638. X
  1639. X   /* CODE */
  1640. X
  1641. X   /* Initialize the local variables. */
  1642. X
  1643. X   read_bytes = input_bytes;
  1644. X   write_bytes = output_bytes;
  1645. X   store_ptr = address;
  1646. X   
  1647. X   /* Check for an even input count. */
  1648. X
  1649. X   if ((read_bytes % 2) == 0)
  1650. X   {
  1651. X      /* Even so input data is in pairs as required. So store the data. */
  1652. X   
  1653. X      while ((read_bytes != 0) && (write_bytes != 0))
  1654. X      {
  1655. X         /* First get the replicate count and the byte to store. */
  1656. X
  1657. X         replicate_count = (unsigned char) Get_Character();
  1658. X         input_char = (invert ? ~Get_Character() : Get_Character());
  1659. X         read_bytes -= 2;
  1660. X      
  1661. X         /* Since write_bytes was 0 there is room to store the byte. */
  1662. X
  1663. X         *store_ptr++ = input_char;
  1664. X         write_bytes--;
  1665. X         
  1666. X         /* Now make sure there is room for the replicated data. */
  1667. X
  1668. X         if (replicate_count > write_bytes)
  1669. X         {
  1670. X            /* Too much so limit to the room available. */
  1671. X
  1672. X            replicate_count = write_bytes;
  1673. X         }
  1674. X            
  1675. X         /* Update the amount to be written. */
  1676. X
  1677. X         write_bytes -= replicate_count;
  1678. X
  1679. X         /* Then replicate it. */
  1680. X
  1681. X         while (replicate_count != 0)
  1682. X         {
  1683. X            /* Store the byte the decrement the count. */
  1684. X
  1685. X            *store_ptr++ = input_char;
  1686. X         
  1687. X            replicate_count--;
  1688. X         }
  1689. X      }
  1690. X
  1691. X   }
  1692. X   /* Discard any left over input. */
  1693. X    /* OR */
  1694. X   /* Discard all of the input data as odd byte count. */
  1695. X
  1696. X   Discard_Block(read_bytes);
  1697. X
  1698. X   read_bytes = store_ptr - address;  /* how much was done? */
  1699. X
  1700. X   /* zero fill if needed */
  1701. X   memset(store_ptr, 0, write_bytes);
  1702. X         
  1703. X   return(read_bytes);
  1704. X}
  1705. X
  1706. X/* $PAGE$ */
  1707. X/*-----------------------------------------------------------------------*\
  1708. X |                                                                       |
  1709. X |  Function Name: Mode_2_Graphics                                       |
  1710. X |                                                                       |
  1711. X |  Description:                                                         |
  1712. X |                                                                       |
  1713. X |  This is the routine that handles a Mode 2 graphics block transfer    |
  1714. X |  to the Formatter Module.  Mode 2 graphics is a compacted mode.       |
  1715. X |  The data in Mode 2 is of one of two types.  The first type is a      |
  1716. X |  class type and the second type is a data type.  The class type is    |
  1717. X |  a single byte which is a combination of replicate count and a sub    |
  1718. X |  mode.  There are two sub modes within mode 2, sub mode 0 and sub     |
  1719. X |  mode 1.  These sub modes are flagged by the MSB of the class type    |
  1720. X |  byte.  If the MSB = 0 then the replicate count is the value of the   |
  1721. X |  class type byte.  In sub mode 0 the replicate count ranges from 1    |
  1722. X |  to 127.  In sub mode 0 the next byte and then the replicate count    |
  1723. X |  of bytes are of the data type and stored.  If the MSB = 1 then the   |
  1724. X |  sub mode is 1 and the replicate count is the negative value of the   |
  1725. X |  class type.  In sub mode 1 the replicate count is stored in 2s       |
  1726. X |  compliment form and ranges from -1 to -127.  In sub mode 1 the       |
  1727. X |  next byte is of the data type and is stored.  That data byte is      |
  1728. X |  then replicated and stored the replicate count.  If the class type   |
  1729. X |  byte is 128 then there is no data type byte.                         |
  1730. X |                                                                       |
  1731. X\*-----------------------------------------------------------------------*/
  1732. X
  1733. X/* FUNCTION */
  1734. X
  1735. XMode_2_Graphics(input_bytes, output_bytes, address, invert)
  1736. X
  1737. Xunsigned int
  1738. X   input_bytes,                 /* Count of bytes to be read. */
  1739. X   output_bytes;                /* Count of bytes to be stored. */
  1740. X
  1741. Xunsigned char
  1742. X   *address;                    /* Pointer to where to store bytes. */
  1743. X
  1744. Xunsigned char            /* Boolean to request data inversion */
  1745. X    invert;
  1746. X
  1747. X{
  1748. X   /* LOCAL VARIABLES */
  1749. X
  1750. X   unsigned char
  1751. X      *store_ptr,               /* Pointer to where to store the byte. */
  1752. X      input_char,               /* Byte to be replicated. */
  1753. X      sub_mode;                 /* Flag if sub mode is 0 or 1. */
  1754. X
  1755. X   unsigned int
  1756. X      read_bytes,               /* Local copy of input_bytes. */
  1757. X      write_bytes;              /* Local copy of output_bytes. */
  1758. X
  1759. X   int
  1760. X      replicate_count;          /* Number of times to replicate data. */
  1761. X
  1762. X   /* CODE */
  1763. X
  1764. X   /* Initialize the local variables. */
  1765. X
  1766. X   read_bytes = input_bytes;
  1767. X   write_bytes = output_bytes;
  1768. X   store_ptr = address;
  1769. X   
  1770. X   while ((read_bytes > 1) && (write_bytes != 0))
  1771. X   {
  1772. X      /* First get the class type byte and the first data type byte. */
  1773. X
  1774. X      replicate_count = Get_Character();
  1775. X
  1776. X      /* First check that this not an ignore class type. */
  1777. X
  1778. X      if (replicate_count != 128)
  1779. X      {
  1780. X         /* Not ignore so get the data class byte. */
  1781. X
  1782. X         input_char = (invert ? ~Get_Character() : Get_Character());
  1783. X         read_bytes -= 2;
  1784. X         
  1785. X        /* Since write_bytes wasn't 0 there is room to store the byte. */
  1786. X
  1787. X         *store_ptr++ = input_char;
  1788. X         write_bytes--;
  1789. X
  1790. X         /* Determine the sub mode. */
  1791. X   
  1792. X         if (replicate_count > 128)
  1793. X         {
  1794. X            /* Sub mode 1. */
  1795. X   
  1796. X            sub_mode = 1;
  1797. X            /* replicate count was unsigned char */
  1798. X            replicate_count = 256 - replicate_count;
  1799. X         }
  1800. X         else
  1801. X         {
  1802. X            /* Sub mode 0. */
  1803. X   
  1804. X            sub_mode = 0;
  1805. X
  1806. X            /* See if there is enoungh input left for the data byte count. */
  1807. X
  1808. X            if (replicate_count > read_bytes)
  1809. X            {
  1810. X               /* Too many data bytes so limit to the input left. */
  1811. X
  1812. X               replicate_count = read_bytes;
  1813. X            }
  1814. X         }
  1815. X            
  1816. X         /* Now make sure there is room for the replicated data. */
  1817. X   
  1818. X         if (replicate_count > write_bytes)
  1819. X         {
  1820. X            /* Too much so limit to the room available. */
  1821. X   
  1822. X            replicate_count = write_bytes;
  1823. X         }
  1824. X               
  1825. X         /* Update the amount to be written. */
  1826. X   
  1827. X         write_bytes -= replicate_count;
  1828. X   
  1829. X         /* Then replicate it. */
  1830. X   
  1831. X         if (sub_mode == 0)
  1832. X         {
  1833. X            /* Sub mode 0 so get the replicate count of data bytes. */
  1834. X   
  1835. X            if (invert)
  1836. X              Inv_Transfer_Block(replicate_count, store_ptr);
  1837. X            else
  1838. X              Transfer_Block(replicate_count, store_ptr);
  1839. X
  1840. X            read_bytes -= replicate_count;
  1841. X            
  1842. X            /* Find the last byte stored. */
  1843. X   
  1844. X            store_ptr += replicate_count;
  1845. X         }
  1846. X         else
  1847. X         {
  1848. X            /* Sub mode 1 so just duplicate the original byte. */
  1849. X   
  1850. X            while (replicate_count != 0)
  1851. X            {
  1852. X               /* Store the byte the decrement the count. */
  1853. X   
  1854. X               *store_ptr++ = input_char;
  1855. X            
  1856. X               replicate_count--;
  1857. X            }
  1858. X         }
  1859. X      }
  1860. X      else
  1861. X      {
  1862. X         /* Ignore class so don't get the data class byte. */
  1863. X
  1864. X         read_bytes--;
  1865. X      }
  1866. X   }
  1867. X
  1868. X   /* Now discard any left over input. */
  1869. X
  1870. X   Discard_Block(read_bytes);
  1871. X
  1872. X   read_bytes = store_ptr - address;
  1873. X
  1874. X   /* zero fill if needed */
  1875. X   memset(store_ptr, 0, write_bytes);
  1876. X         
  1877. X   
  1878. X   return(read_bytes);
  1879. X}
  1880. X
  1881. X/* $PAGE$ */
  1882. X/*-----------------------------------------------------------------------*\
  1883. X |                                                                       |
  1884. X |  Function Name: Mode_3_Graphics                                       |
  1885. X |                                                                       |
  1886. X |  Description:                                                         |
  1887. X |                                                                       |
  1888. X |  This is the routine that handles a Mode 3 graphics block transfer    |
  1889. X |  to the Formatter Module.  Mode 3 graphics is a compacted mode.       |
  1890. X |  Mode 3 data is a difference from one row to the next.  In order to   |
  1891. X |  work, each row must be saved to be a seed for the next.  This        |
  1892. X |  mode is used in conjuction with other compaction modes when the      |
  1893. X |  data remains fairly constant between pairs of rows.                  |
  1894. X |  The data is in the form:                                             |
  1895. X |  <command byte>[<optional offset bytes>]<1 to 8 replacement bytes>    |
  1896. X |  The command byte is in the form:                                     |
  1897. X |    Bits 5-7: Number of bytes to replace (1 - 8)                       |
  1898. X |    Bits 0-4: Relative offset from last byte.                          |
  1899. X |       (If the offset is 31, then add the following bytes for offset   |
  1900. X |       until an offset byte of less then 255 (but inclusive)           |
  1901. X |                                                                       |
  1902. X\*-----------------------------------------------------------------------*/
  1903. X
  1904. X/* FUNCTION */
  1905. X
  1906. XMode_3_Graphics(input_bytes, output_bytes, address, invert)
  1907. X
  1908. Xunsigned int
  1909. X   input_bytes,                 /* Count of bytes to be read. */
  1910. X   output_bytes;                /* Count of bytes to be stored. */
  1911. X
  1912. Xunsigned char
  1913. X   *address;                    /* Pointer to where to store bytes. */
  1914. X
  1915. Xunsigned char            /* Boolean to request data inversion */
  1916. X    invert;
  1917. X
  1918. X{
  1919. X   /* LOCAL VARIABLES */
  1920. X
  1921. X   unsigned char
  1922. X      *store_ptr,               /* Pointer to where to store the byte. */
  1923. X      input_char;               /* Byte to be changed. */
  1924. X
  1925. X   unsigned int
  1926. X      read_bytes,               /* Local copy of input_bytes. */
  1927. X      write_bytes;              /* Local copy of output_bytes. */
  1928. X
  1929. X   unsigned int
  1930. X      replace,            /* number of bytes to replace, 1-8 */
  1931. X      offset;            /* relative offset */
  1932. X
  1933. X#if BITFIELDS
  1934. X   union comtype {
  1935. X      unsigned char comchar;    /* command byte as char */
  1936. X      struct btype {
  1937. X     unsigned repcount:3;    /* replace count 1-8 */
  1938. X     unsigned roff:5;    /* relative offset 0-30 */
  1939. X      } bitf;
  1940. X   } command;
  1941. X#else
  1942. X    unsigned char    command;
  1943. X#endif
  1944. X
  1945. X   /* CODE */
  1946. X
  1947. X   /* Initialize the local variables. */
  1948. X
  1949. X   read_bytes = input_bytes;
  1950. X   write_bytes = output_bytes;
  1951. X   store_ptr = address;
  1952. X
  1953. X/* read_bytes has to be at least 2 to be valid */
  1954. X
  1955. X   while ( read_bytes > 1 && write_bytes > 0 ){
  1956. X
  1957. X      /* start by getting the command byte */
  1958. X
  1959. X      read_bytes--;
  1960. X
  1961. X#if BITFIELDS
  1962. X      command.comchar = Get_Character();
  1963. X
  1964. X      replace = command.bitf.repcount + 1;    /* replace count 1-8 */
  1965. X
  1966. X      offset = command.bitf.roff;        /* offset 0-30, 31= extend */
  1967. X#else
  1968. X    command = Get_Character();
  1969. X    replace = (command >> 5) + 1;
  1970. X    offset = command & 0x1f;
  1971. X#endif
  1972. X
  1973. X      store_ptr += offset;
  1974. X      write_bytes -= offset;
  1975. X
  1976. X      if ( offset == 31 )        /* get more offsets */
  1977. X     do{
  1978. X
  1979. X        offset = Get_Character();
  1980. X
  1981. X        read_bytes--;
  1982. X            if ( read_bytes == 0 )        /* premature finish? */
  1983. X           return;                /* no zero fill wih 3 */
  1984. X
  1985. X        store_ptr += offset;
  1986. X            write_bytes -= offset;
  1987. X
  1988. X     } while (offset == 255);    /* 255 = keep going */
  1989. X      
  1990. X      /* now do the byte replacement */
  1991. X
  1992. X      while ( replace-- && write_bytes > 0 && read_bytes > 0 ){
  1993. X     
  1994. X     *store_ptr++ = (invert ? ~Get_Character() : Get_Character() );
  1995. X
  1996. X     read_bytes--;
  1997. X     write_bytes--;
  1998. X      }
  1999. X   }
  2000. X   
  2001. X   /* don't do any zero fill with mode 3 */
  2002. X
  2003. X   /* discard any leftover input */
  2004. X
  2005. X   Discard_Block(read_bytes);
  2006. X
  2007. X   return( store_ptr - address );
  2008. X}
  2009. X
  2010. X
  2011. XDiscard_Block(count)
  2012. Xunsigned int count;
  2013. X{
  2014. X    while ( count-- )
  2015. X        getchar();
  2016. X}
  2017. X
  2018. XTransfer_Block( count, dest )
  2019. Xunsigned int count;
  2020. Xunsigned char *dest;
  2021. X{
  2022. X    fread(dest, 1, count, stdin);
  2023. X}
  2024. X
  2025. X/* this doesn't invert at the moment */
  2026. X
  2027. XInv_Transfer_Block( count, dest )
  2028. Xunsigned int count;
  2029. Xunsigned char *dest;
  2030. X{
  2031. X    fread(dest, 1, count, stdin);
  2032. X}
  2033. X
  2034. X
  2035. XOutput_0(src, dest, count)
  2036. Xunsigned char *src, *dest;
  2037. Xint count;
  2038. X{
  2039. X    memcpy(dest, src, count);
  2040. X
  2041. X    if ( zerostrip )
  2042. X        while ( count && dest[count-1] == 0 )
  2043. X            count--;
  2044. X
  2045. X    return(count);
  2046. X
  2047. X}
  2048. X
  2049. XOutput_1(src, dest, count)
  2050. Xunsigned char *src, *dest;
  2051. Xregister int count;
  2052. X{
  2053. X    unsigned char *optr = dest, *iptr;
  2054. X    int k,c;
  2055. X
  2056. X    if ( zerostrip )            /* strip zeros */
  2057. X    {
  2058. X        iptr = src + count - 1;        /* point to end of data */
  2059. X
  2060. X        while ( count > 0 && *iptr-- == 0 )    /* hunt thru 0's */
  2061. X            count--;
  2062. X    }
  2063. X
  2064. X    iptr = src;
  2065. X
  2066. X    while ( count ){
  2067. X        
  2068. X        c = *iptr++;        /* get value to work with */
  2069. X        count--;
  2070. X
  2071. X        k = 0;
  2072. X
  2073. X        while ( *iptr == c && k < 255 && count ){
  2074. X            k++;
  2075. X            iptr++;
  2076. X            count--;
  2077. X        }
  2078. X
  2079. X        *optr++ = k;        /* output repeat count */
  2080. X        *optr++ = c;        /* output value */
  2081. X    }
  2082. X
  2083. X    count = optr - dest;        /* for return value */
  2084. X
  2085. X    return ( count );
  2086. X}
  2087. X
  2088. X
  2089. XOutput_2(src, dest, count)
  2090. Xunsigned char *src, *dest;
  2091. Xregister int count;
  2092. X{
  2093. X    unsigned char *optr = dest, *iptr;
  2094. X    int k,c;
  2095. X    unsigned char *tptr, *tptr1, *tptr2;
  2096. X    int tk,tc;
  2097. X
  2098. X
  2099. X    if ( zerostrip )            /* strip zeros */
  2100. X    {
  2101. X        iptr = src + count - 1;        /* point to end of data */
  2102. X
  2103. X        while ( count > 0 && *iptr-- == 0 )    /* hunt thru 0's */
  2104. X            count--;
  2105. X    }
  2106. X
  2107. X    iptr = src;
  2108. X
  2109. X    while ( count ){
  2110. X        
  2111. X        c = *iptr++;        /* get value to work with */
  2112. X        count--;
  2113. X
  2114. X        k = 0;
  2115. X
  2116. X        while ( *iptr == c && k < 127 && count ){
  2117. X            k++;
  2118. X            iptr++;
  2119. X            count--;
  2120. X        }
  2121. X
  2122. X        if ( k >= 1 ){
  2123. X            *optr++ = 256 - k;    /* output repeat count */
  2124. X            *optr++ = c;        /* output value */
  2125. X        } else {
  2126. X                    /* a two byte replicate run will
  2127. X                     * be sent as a repeated byte 
  2128. X                     * unless it is preceeded and
  2129. X                     * and followed by a literal run,
  2130. X                     * in which case it is merged
  2131. X                     * into the run.
  2132. X                     */
  2133. X            tk = 0;
  2134. X            tc = c;
  2135. X            tptr = iptr;
  2136. X            tptr1 = tptr;
  2137. X            tptr1++;
  2138. X            tptr2 = tptr1;
  2139. X            tptr2++;
  2140. X
  2141. X            while ( tk < 128 && (count - tk) > 0    && 
  2142. X                ((*tptr != tc) || (*tptr == tc &&
  2143. X                                   (count - tk - 1) > 0 &&
  2144. X                                   *tptr1 != *tptr &&
  2145. X                                   *tptr2 != *tptr1))){
  2146. X
  2147. X                tc = *tptr++;
  2148. X                tk++;
  2149. X                tptr1++;
  2150. X                tptr2++;
  2151. X            }
  2152. X
  2153. X            if ( count && tk )
  2154. X                tk--;
  2155. X
  2156. X            *optr++ = tk;        /* output count */
  2157. X            *optr++ = c;        /* output firstvalue */
  2158. X
  2159. X            while ( tk-- > 0){
  2160. X                *optr++ = *iptr++;
  2161. X                count--;
  2162. X            }
  2163. X
  2164. X        }
  2165. X    }
  2166. X
  2167. X    count = optr - dest;        /* for return value */
  2168. X
  2169. X    return ( count );
  2170. X}
  2171. X
  2172. XOutput_3(seed, new, dest, count)
  2173. Xunsigned char *seed, *new, *dest;
  2174. Xint count;
  2175. X{
  2176. X    unsigned char *sptr=seed, *nptr=new, *dptr=dest;
  2177. X    int i,j;
  2178. X
  2179. X
  2180. X#if BITFIELDS
  2181. X   union comtype {
  2182. X      unsigned char comchar;    /* command byte as char */
  2183. X      struct btype {
  2184. X     unsigned repcount:3;    /* replace count 1-8 */
  2185. X     unsigned roff:5;    /* relative offset 0-30 */
  2186. X      } bitf;
  2187. X   } command;
  2188. X#else
  2189. X    unsigned char    command;
  2190. X#endif
  2191. X
  2192. X    while ( count > 0 ){
  2193. X        i = 0;
  2194. X
  2195. X                    /* find first diff */
  2196. X        while ( *sptr == *nptr && i < count ){
  2197. X            i++;
  2198. X            sptr++;
  2199. X            nptr++;
  2200. X        }
  2201. X
  2202. X        if ( i >= count )    /* too far to find diff */
  2203. X            return(dptr - dest);    /* bail */
  2204. X
  2205. X        count -= i;
  2206. X        
  2207. X        /* now count how many bytes to change */
  2208. X
  2209. X        for ( j = 1; j < 8; j++)    /* j == 0 is already known */
  2210. X            if ( j > count || sptr[j] == nptr[j] )
  2211. X                break;
  2212. X        
  2213. X        j--;    /* adjust */
  2214. X
  2215. X#if BITFIELDS
  2216. X        command.bitf.repcount = j;    /* 0-7 ==> 1-8 */
  2217. X
  2218. X        command.bitf.roff = MIN ( i, 31 );
  2219. X
  2220. X        *dptr++ = command.comchar;    /* output command */
  2221. X#else
  2222. X        command = (j << 5);
  2223. X        command += MIN( i, 31 );
  2224. X        *dptr++ = command;
  2225. X#endif
  2226. X
  2227. X        if ( i == 31 )
  2228. X            *dptr++ = 0;
  2229. X        
  2230. X        i -= MIN (i, 31);
  2231. X
  2232. X        while( i ){
  2233. X            *dptr++ = MIN ( i, 255 );
  2234. X
  2235. X            if ( i == 255 )
  2236. X                *dptr++ = 0;
  2237. X            
  2238. X            i -= MIN ( i, 255 );
  2239. X        }
  2240. X
  2241. X        while (j-- >= 0){
  2242. X            *dptr++ = *nptr++;
  2243. X            sptr++;
  2244. X            count--;
  2245. X        }
  2246. X    }
  2247. X
  2248. X    return ( dptr - dest );
  2249. X}
  2250. X
  2251. X
  2252. X/*----------------------------------------------------------------------*\
  2253. X * This is here in case <ESC>*rU is sent after <ESC>*r#A, in which case *
  2254. X * we must deallocate the memory to provide for a different amount of   *
  2255. X * planes when graphics are sent.                                       *
  2256. X\*----------------------------------------------------------------------*/
  2257. X
  2258. Xfree_mem()    
  2259. X{
  2260. X    int r;
  2261. X
  2262. X
  2263. X    if ( !memflag )
  2264. X        return;        /* no memory to free */
  2265. X
  2266. X    free(new_row);
  2267. X
  2268. X    for(r = MAXMODES -1; r >= 0; r--)
  2269. X        free(out_row[r]);
  2270. X
  2271. X    for(r = num_planes - 1; r >= 0; r--)
  2272. X        free(seed_row[r]);
  2273. X
  2274. X    memflag = FALSE;
  2275. X}
  2276. END_OF_FILE
  2277.   if test 52617 -ne `wc -c <'pclcomp.c'`; then
  2278.     echo shar: \"'pclcomp.c'\" unpacked with wrong size!
  2279.   fi
  2280.   # end of 'pclcomp.c'
  2281. fi
  2282. echo shar: End of archive 2 \(of 2\).
  2283. cp /dev/null ark2isdone
  2284. MISSING=""
  2285. for I in 1 2 ; do
  2286.     if test ! -f ark${I}isdone ; then
  2287.     MISSING="${MISSING} ${I}"
  2288.     fi
  2289. done
  2290. if test "${MISSING}" = "" ; then
  2291.     echo You have unpacked both archives.
  2292.     rm -f ark[1-9]isdone
  2293. else
  2294.     echo You still must unpack the following archives:
  2295.     echo "        " ${MISSING}
  2296. fi
  2297. exit 0
  2298. exit 0 # Just in case...
  2299. -- 
  2300. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  2301. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  2302. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  2303. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  2304.